package com.example.demo;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 简单封装Jackson，实现JSON String<->Java Object的Mapper.
 * 封装不同的输出风格, 使用不同的builder函数创建实例.
 *
 * @author fanhaibo_900 from free lance
 * time 2018年6月24日1
 */
public class JsonMapper {
    private JsonMapper() {
    }

    private static Logger logger = LoggerFactory.getLogger(JsonMapper.class);

    private static ObjectMapper mapper;
    private static ObjectMapper quotesMapper;
    private static ObjectMapper nonEmptyMapper;
    private static ObjectMapper nonNullMapper;

    /** 允许单引号, 允许不带引号的字段名称 */
    static {
        mapper = new ObjectMapper();
        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

    }

    /* String类型null默认值为空字符串 */
    static {
        quotesMapper = new ObjectMapper();
        quotesMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        quotesMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        quotesMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
            @Override
            public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                jsonGenerator.writeString("");
            }
        });
    }

    static {
        nonEmptyMapper = new ObjectMapper();
        nonEmptyMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        nonEmptyMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        nonEmptyMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
    }

    static {
        nonNullMapper = new ObjectMapper();
        nonNullMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        nonNullMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        nonNullMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    }


    /**
     * Object转Json
     */
    public static String toJson(Object val) {
        //字符串不做处理
        if (val instanceof String) {
            return (String) val;
        }

        if (val != null) {
            try {
                return mapper.writeValueAsString(val);
            } catch (IOException e) {
                logger.warn("write to json string error:" + val, e);
            }
        }
        return null;
    }

    /**
     * Object转Json
     */
    public static String toJsonNonNull(Object val) {
        //字符串不做处理
        if (val instanceof String) {
            return (String) val;
        }

        if (val != null) {
            try {
                return nonNullMapper.writeValueAsString(val);
            } catch (IOException e) {
                logger.warn("write to json string error:" + val, e);
            }
        }
        return null;
    }

    /**
     * Object转Json
     */
    public static String toJsonNonEmpty(Object val) {
        //字符串不做处理
        if (val instanceof String) {
            return (String) val;
        }

        if (val != null) {
            try {
                return nonEmptyMapper.writeValueAsString(val);
            } catch (IOException e) {
                logger.warn("write to json string error:" + val, e);
            }
        }
        return null;
    }


    /**
     * JSON转Map<String,Object>
     *
     * @param json
     * @return
     */
    public static Map<String, Object> getMap(String json) {
        return getObjectByType(json, new TypeReference<Map<String, Object>>() {
        });
    }

    public static Map<String, Object> getNoNullMap(Object obj) {
        return nonNullMapper.convertValue(obj, new TypeReference<Map<String, Object>>() {
        });
    }

    /**
     * JSON转Map<String,Object>
     *
     * @param json
     * @return
     */
    public static <T> List<T> getList(String json) {
        return getObjectByType(json, new TypeReference<List<T>>() {
        });
    }

    /**
     * 利用TypeReference 把JSON转Object  //...test git
     */
    public static <T> T getObjectByType(String json, TypeReference<T> tr) {
        if (StringUtils.isNotBlank(json)) {
            return doGetObjectByType(json, tr);
        }
        return null;
    }

    public static <T> T get(String json, Class<T> clz) {
        return doGetObjectByType(json, clz);
    }

    @SuppressWarnings("unchecked")
    private static <T> T doGetObjectByType(String json, Object clz) {
        try {
            if (clz instanceof Class) {
                return (T) mapper.readValue(json, (Class) clz);
            } else if (clz instanceof TypeReference) {
                return (T) mapper.readValue(json, (TypeReference) clz);
            } else {
                logger.error("parameter error , only TypeReference or Class");
            }
        } catch (JsonParseException e) {
            logger.error("parse json string error(JsonParseException):" + json, e);
        } catch (JsonMappingException e) {
            logger.error("parse json string error(JsonMappingException):" + json, e);
        } catch (IOException e) {
            logger.error("parse json string error(IOException):" + json, e);
        }
        return null;
    }


    private static String getLevelStr(int level) {
        StringBuilder levelStr = new StringBuilder();
        for (int levelI = 0; levelI < level; levelI++) {
            levelStr.append("\t");
        }
        return levelStr.toString();
    }

    /**
     * 格式化JSON字符串
     *
     * @param json
     * @return
     */
    public static String formatJson(String json) {
        int level = 0;
        StringBuilder jsonForMatStr = new StringBuilder();
        for (int index = 0; index < json.length(); index++)// 将字符串中的字符逐个按行输出
        {
            // 获取s中的每个字符
            char c = json.charAt(index);

            // level大于0并且jsonForMatStr中的最后一个字符为\n,jsonForMatStr加入\t
            if (level > 0 && '\n' == jsonForMatStr.charAt(jsonForMatStr.length() - 1)) {
                jsonForMatStr.append(getLevelStr(level));
            }
            // 遇到"{"和"["要增加空格和换行，遇到"}"和"]"要减少空格，以对应，遇到","要换行
            switch (c) {
                case '{':
                case '[':
                    jsonForMatStr.append(c + "\n");
                    level++;
                    break;
                case ',':
                    jsonForMatStr.append(c + "\n");
                    break;
                case '}':
                case ']':
                    jsonForMatStr.append("\n");
                    level--;
                    jsonForMatStr.append(getLevelStr(level));
                    jsonForMatStr.append(c);
                    break;
                default:
                    jsonForMatStr.append(c);
                    break;
            }
        }
        return jsonForMatStr.toString();

    }

    public static ObjectMapper getMapper() {
        return mapper;
    }

    @SuppressWarnings("All")
    public static Map<String, Object> convert(Object obj) {
        return mapper.convertValue(obj, HashMap.class);
    }

    //字段的值既不能为“”，也不能为null
    public static ObjectMapper getNonEmptyMapper() {
        return nonEmptyMapper;
    }

    //字段值可以为“”，但是不能为null
    public static ObjectMapper getNonNullMapper() {
        return nonNullMapper;
    }

    //默认字符串值为""
    public static ObjectMapper getQuotesMapper() {
        return quotesMapper;
    }


}
